home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 21 / CU Amiga Magazine's Super CD-ROM 21 (1998)(EMAP Images)(GB)[!][issue 1998-04].iso / CUCD / Programming / Python-1.4 / Source / Amiga / Python_netlib / rcmd.c < prev    next >
C/C++ Source or Header  |  1994-09-29  |  10KB  |  317 lines

  1. RCS_ID_C = "$Id: rcmd.c,v 4.2 1994/09/29 23:09:02 jraja Exp $";
  2. /*
  3.  *      rcmd.c - rcmd() for AmiTCP/IP and usergroup.library
  4.  *
  5.  *      Copyright © 1994 AmiTCP/IP Group, 
  6.  *                       Network Solutions Development Inc.
  7.  *                       All rights reserved.
  8.  */
  9.  
  10. /*
  11.  * Copyright (c) 1983 Regents of the University of California.
  12.  * All rights reserved.
  13.  *
  14.  * Redistribution and use in source and binary forms, with or without
  15.  * modification, are permitted provided that the following conditions
  16.  * are met:
  17.  * 1. Redistributions of source code must retain the above copyright
  18.  *    notice, this list of conditions and the following disclaimer.
  19.  * 2. Redistributions in binary form must reproduce the above copyright
  20.  *    notice, this list of conditions and the following disclaimer in the
  21.  *    documentation and/or other materials provided with the distribution.
  22.  * 3. All advertising materials mentioning features or use of this software
  23.  *    must display the following acknowledgement:
  24.  *    This product includes software developed by the University of
  25.  *    California, Berkeley and its contributors.
  26.  * 4. Neither the name of the University nor the names of its contributors
  27.  *    may be used to endorse or promote products derived from this software
  28.  *    without specific prior written permission.
  29.  *
  30.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  31.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  32.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  33.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  34.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  35.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  36.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  37.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  38.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  39.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  40.  * SUCH DAMAGE.
  41.  */
  42.  
  43. #if __SASC
  44. #include <proto/dos.h>
  45. #include <proto/socket.h>
  46. #include <proto/exec.h>
  47. #elif __GNUC__
  48. #include <inline/dos.h>
  49. #include <inline/socket.h>
  50. #include <inline/exec.h>
  51. #else
  52. #include <clib/dos_protos.h>
  53. #include <clib/socket_protos.h>
  54. #include <clib/exec_protos.h>
  55. #endif
  56.  
  57. #include <sys/param.h>
  58. #include <sys/ioctl.h>
  59. #include <sys/socket.h>
  60. #include <sys/stat.h>
  61. #include <netinet/in.h>
  62. #include <arpa/inet.h>
  63. #if 0
  64. #include <signal.h>
  65. #endif
  66. #include <fcntl.h>
  67. #include <netdb.h>
  68. #include <pwd.h>
  69. #include <errno.h>
  70. #include <stdio.h>
  71. #include <ctype.h>
  72.  
  73. #include <unistd.h>
  74. #include <string.h>
  75.  
  76. #ifdef ioctl
  77. #undef ioctl
  78. #endif
  79. #ifdef close
  80. #undef close
  81. #endif
  82. #define ioctl IoctlSocket
  83. #define close CloseSocket
  84. #define getpid() ((pid_t)FindTask(0L))
  85.  
  86.  
  87. /****** net.lib/rcmd *********************************************************
  88.  
  89.     NAME
  90.         rcmd, rresvport - routines for returning a stream to a remote command
  91.  
  92.     SYNOPSIS
  93.         #include <clib/socket_protos.h>
  94.  
  95.         int rcmd(char **ahost, int inport, const char *locuser, 
  96.                  const char *remuser, const char *cmd, int *fd2p);
  97.  
  98.         int rresvport(int *port);
  99.  
  100.     FUNCTION
  101.         The rcmd() function is used by the super-user to execute a command on
  102.         a remote machine using an authentication scheme based on reserved port
  103.         numbers.  The rresvport() function returns a descriptor to a socket
  104.         with an address in the privileged port space.  Both functions are
  105.         present in the same file and are used by the rsh command (among
  106.         others).
  107.  
  108.         The rcmd() function looks up the host *ahost using gethostbyname(),
  109.         returning -1 if the host does not exist.  Otherwise *ahost is set to
  110.         the standard name of the host and a connection is established to a
  111.         server residing at the well-known Internet port inport.
  112.  
  113.         If the connection succeeds, a socket in the Internet domain of type
  114.         SOCK_STREAM is returned to the caller, and given to the remote command
  115.         as stdin and stdout. If fd2p is non-zero, then an auxiliary channel to
  116.         a control process will be set up, and a descriptor for it will be
  117.         placed in *fd2p. The control process will return diagnostic output
  118.         from the command (unit 2) on this channel, and will also accept bytes
  119.         on this channel as being UNIX signal numbers, to be forwarded to the
  120.         process group of the command.  If fd2p is 0, then the stderr (unit 2
  121.         of the remote command) will be made the same as the stdout and no
  122.         provision is made for sending arbitrary signals to the remote process,
  123.         although you may be able to get its attention by using out-of-band
  124.         data.
  125.  
  126.         The protocol is described in detail in netutil/rshd.
  127.  
  128.         The rresvport() function is used to obtain a socket with a privileged
  129.         address bound to it.  This socket is suitable for use by rcmd() and
  130.         several other functions.  Privileged Internet ports are those in the
  131.         range 0 to 1023.  Only the super-user is allowed to bind an address of
  132.         this sort to a socket.
  133.  
  134.     DIAGNOSTICS
  135.         The rcmd() function returns a valid socket descriptor on success.  It
  136.         returns -1 on error and prints a diagnostic message on the standard
  137.         error.
  138.  
  139.         The rresvport() function returns a valid, bound socket descriptor on
  140.         success.  It returns -1 on error with the global value errno set
  141.         according to the reason for failure.  The error code EAGAIN is
  142.         overloaded to mean `All network ports in use.'
  143.  
  144.     SEE ALSO
  145.         netutil/rlogin,  netutil/rsh,  rexec(),  netutil/rexecd,
  146.         netutil/rlogind, netutil/rshd
  147.  
  148. ******************************************************************************
  149. */
  150.  
  151. #include <clib/netlib_protos.h>
  152.  
  153. int
  154. rcmd(char **ahost,
  155.      int rport,
  156.      const char *locuser, 
  157.      const char *remuser, 
  158.      const char *cmd,
  159.      int *fd2p)            /* Socket for stderr  */
  160. {
  161.   int s, timo = 1;
  162.   pid_t pid;
  163.   struct sockaddr_in sin, from;
  164.   char c;
  165.   int lport = IPPORT_RESERVED - 1;
  166.   struct hostent *hp;
  167.   fd_set reads;
  168.  
  169.   pid = getpid();
  170.   hp = gethostbyname(*ahost);
  171.   if (hp == 0) {
  172.     herror(*ahost);
  173.     errno = EADDRNOTAVAIL;
  174.     return (-1);
  175.   }
  176.   *ahost = hp->h_name;
  177.  
  178.   for (;;) {
  179.     s = rresvport(&lport);
  180.     if (s < 0) {
  181.       errno == EAGAIN ? 
  182.     fprintf(stderr, "socket: All ports in use\n")
  183.       : perror("rcmd: socket");
  184.       return (-1);
  185.     }
  186.     ioctl(s, FIOSETOWN, (caddr_t)&pid);
  187.     sin.sin_len = sizeof(sin);
  188.     sin.sin_family = hp->h_addrtype;
  189.     bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, hp->h_length);
  190.     sin.sin_port = rport;
  191.     if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
  192.       break;
  193.     (void) close(s);
  194.     if (errno == EADDRINUSE) {
  195.       lport--;
  196.       continue;
  197.     }
  198.     if (errno == ECONNREFUSED && timo <= 16) {
  199.       sleep(timo);
  200.       timo *= 2;
  201.       continue;
  202.     }
  203.     if (hp->h_addr_list[1] != NULL) {
  204.       int oerrno = errno;
  205.  
  206.       fprintf(stderr, "connect to address %s: ", inet_ntoa(sin.sin_addr));
  207.       errno = oerrno;
  208.       perror("");
  209.       hp->h_addr_list++;
  210.       bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, hp->h_length);
  211.       fprintf(stderr, "Trying %s...\n", inet_ntoa(sin.sin_addr));
  212.       continue;
  213.     }
  214.     perror(hp->h_name);
  215.     return (-1);
  216.   }
  217.  
  218.   lport--;
  219.   if (fd2p == 0) {
  220.     send(s, "", 1, 0);
  221.     lport = 0;
  222.   } else {
  223.     char num[8];
  224.     long s2 = rresvport(&lport), s3;
  225.     long len = sizeof (from);
  226.  
  227.     if (s2 < 0)
  228.       goto bad;
  229.     listen(s2, 1);
  230.     (void) sprintf(num, "%ld", lport);
  231.     if (send(s, num, strlen(num)+1, 0) != strlen(num)+1) {
  232.       perror("send: setting up stderr");
  233.       (void) close(s2);
  234.       goto bad;
  235.     }
  236.     FD_ZERO(&reads);
  237.     FD_SET(s, &reads);
  238.     FD_SET(s2, &reads);
  239.     errno = 0;
  240.     if (select(((s > s2) ? s : s2) + 1,
  241.            &reads, 0, 0, 0) < 1 || !FD_ISSET(s2, &reads)) {
  242.       errno != 0 ?
  243.           perror("select: setting up stderr")
  244.       :
  245.       fprintf(stderr, "select: protocol failure in circuit setup.\n");
  246.       (void) close(s2);
  247.       goto bad;
  248.     }
  249.     s3 = accept(s2, (struct sockaddr *)&from, &len);
  250.     (void) close(s2);
  251.     if (s3 < 0) {
  252.       perror("accept");
  253.       lport = 0;
  254.       goto bad;
  255.     }
  256.     *fd2p = s3;
  257.     from.sin_port = ntohs((u_short)from.sin_port);
  258.     if (from.sin_family != AF_INET ||
  259.     from.sin_port >= IPPORT_RESERVED ||
  260.     from.sin_port < IPPORT_RESERVED / 2) {
  261.       fprintf(stderr, "socket: protocol failure in circuit setup.\n");
  262.       goto bad2;
  263.     }
  264.   }
  265.   (void) send(s, locuser, strlen(locuser) + 1, 0);
  266.   (void) send(s, remuser, strlen(remuser) + 1, 0);
  267.   (void) send(s, cmd, strlen(cmd) + 1, 0);
  268.   if (recv(s, &c, 1, 0) != 1) {
  269.     perror(*ahost);
  270.     goto bad2;
  271.   }
  272.   if (c != 0) {
  273.     while (recv(s, &c, 1, 0) == 1) {
  274.       (void) fputc(c, stderr);
  275.       if (c == '\n')
  276.     break;
  277.     }
  278.     goto bad2;
  279.   }
  280.  
  281.   return (s);
  282.  bad2:
  283.   if (lport)
  284.     (void) close(*fd2p);
  285.  bad:
  286.   (void) close(s);
  287.   return (-1);
  288. }
  289.  
  290. int rresvport(int *alport)
  291. {
  292.   struct sockaddr_in sin;
  293.   int s;
  294.  
  295.   sin.sin_len = sizeof(sin);
  296.   sin.sin_family = AF_INET;
  297.   sin.sin_addr.s_addr = INADDR_ANY;
  298.   s = socket(AF_INET, SOCK_STREAM, 0);
  299.   if (s < 0)
  300.     return (-1);
  301.   for (;;) {
  302.     sin.sin_port = htons((u_short)*alport);
  303.     if (bind(s, (struct sockaddr *)&sin, sizeof (sin)) >= 0)
  304.       return (s);
  305.     if (errno != EADDRINUSE) {
  306.       (void) close(s);
  307.       return (-1);
  308.     }
  309.     (*alport)--;
  310.     if (*alport == IPPORT_RESERVED/2) {
  311.       (void) close(s);
  312.       errno = EAGAIN;        /* close */
  313.       return (-1);
  314.     }
  315.   }
  316. }
  317.